package meterMonitor.util;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonMapper {

    private static final Logger       logger = LoggerFactory.getLogger(JacksonMapper.class);

    private static final ObjectMapper mapper = new ObjectMapper();

    private JacksonMapper() {

    }

    /**
     * @return
     */
    public static ObjectMapper getInstance() {
        return mapper;
    }

    /**
     * 将对象转换为JSON字符串
     * 
     * @param value
     *            对象
     * @return JSOn字符串
     */
    public static String toJson(Object value) {
        try {
            return mapper.writeValueAsString(value);
        }
        catch (Exception e) {
            logger.error("将对象转换为JSON字符串异常",e);
        }
        return null;
    }

    /**
     * 将JSON字符串转换为对象
     * 
     * @param json
     *            JSON字符串
     * @param valueType
     *            对象类型
     * @return 对象
     */
    public static <T> T toObject(String json, Class<T> valueType) {
        Assert.hasText(json);
        Assert.notNull(valueType);
        try {
            return mapper.readValue(json, valueType);
        }
        catch (Exception e) {
        	logger.error("JacksonMapper异常", e);
        }
        return null;
    }

    /**
     * 将JSON字符串转换为对象
     * 
     * @param json
     *            JSON字符串
     * @param typeReference
     *            对象类型
     * @return 对象
     */
    public static <T> T toObject(String json, TypeReference<?> typeReference) {
        Assert.hasText(json);
        Assert.notNull(typeReference);
        try {
            return mapper.readValue(json, typeReference);
        }
        catch (Exception e) {
        	        	logger.error("JacksonMapper异常", e);
        }
        return null;
    }

    /**
     * 将JSON字符串转换为对象
     * 
     * @param json
     *            JSON字符串
     * @param javaType
     *            对象类型
     * @return 对象
     */
    public static <T> T toObject(String json, JavaType javaType) {
        Assert.hasText(json);
        Assert.notNull(javaType);
        try {
            return mapper.readValue(json, javaType);
        }
        catch (Exception e) {
        	        	logger.error("JacksonMapper异常", e);
        }
        return null;
    }

    /**
     * 将对象转换为JSON流
     * 
     * @param writer
     *            writer
     * @param value
     *            对象
     */
    public static void writeValue(Writer writer, Object value) {
        try {
            mapper.writeValue(writer, value);
        }
        catch (JsonGenerationException e) {
        	        	logger.error("JacksonMapper异常", e);
        }
        catch (JsonMappingException e) {
        	        	logger.error("JacksonMapper异常", e);
        }
        catch (IOException e) {
        	        	logger.error("JacksonMapper异常", e);
        }
    }

    /**
     * 读取json串中某一个字段的值
     * 
     * @param json
     * @param property
     * @return
     */
    public static Object readValueByProperty(String json, String property) {
        HashMap jsonMap = null;
        try {
            jsonMap = mapper.readValue(json, HashMap.class);
            return jsonMap.get(property);
        }
        catch (IOException e) {
            logger.error("读取配置文件错误：" + e.getLocalizedMessage() + e.getMessage() + e.toString());
        }
        return null;
    }

    /**
     * 将一个 Map 对象转化为一个 JavaBean
     * 
     * @param type
     *            要转化的类型
     * @param map
     *            包含属性值的 map
     * @return 转化出来的 JavaBean 对象
     * @throws IntrospectionException
     *             如果分析类属性失败
     * @throws IllegalAccessException
     *             如果实例化 JavaBean 失败
     * @throws InstantiationException
     *             如果实例化 JavaBean 失败
     * @throws InvocationTargetException
     *             如果调用属性的 setter 方法失败
     */
    @SuppressWarnings("rawtypes")
    public static Object convertMap(Class type, Map map)
            throws IntrospectionException, IllegalAccessException, InstantiationException, InvocationTargetException {
        BeanInfo beanInfo = Introspector.getBeanInfo(type); // 获取类属性
        Object obj = type.newInstance(); // 创建 JavaBean 对象

        // 给 JavaBean 对象的属性赋值
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();

            String propertyType = descriptor.getPropertyType().toString();   // 获取属性类型

            if (map.containsKey(propertyName.toUpperCase())) {
                // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                Object value = map.get(propertyName.toUpperCase());
                try {

                    if (null == value)
                        continue;

                    Object[] args = new Object[1];

                    if (propertyType.equals("class java.lang.Double")) {
                        args[0] = Double.valueOf(String.valueOf(value));
                    }

                    if (propertyType.equals("class java.lang.String")) {
                        args[0] = String.valueOf(value);
                    }

                    if (propertyType.equals("class java.util.Date")) {
                        args[0] = Timestamp.valueOf(String.valueOf(value));
                    }

                    if (propertyType.equals("class java.lang.Long")) {
                        args[0] = Long.valueOf(String.valueOf(value));
                    }

                    if (propertyType.equals("class java.lang.Integer")) {
                        args[0] = Integer.valueOf(String.valueOf(value));
                    }

                    if (propertyType.equals("class java.lang.Boolean")) {
                        args[0] = Boolean.valueOf(String.valueOf(value));
                    }

                    if (propertyType.equals("class java.math.BigDecimal")) {
                        args[0] = BigDecimal.valueOf(Long.valueOf(String.valueOf(value)));
                    }

                    if (propertyType.equals("class java.lang.Short")) {
                        args[0] = Short.valueOf(String.valueOf(value));
                    }
                    descriptor.getWriteMethod().invoke(obj, args);
                }
                catch (Exception e) {
                    logger.error("错误 ： {}", e);
                }
            }
        }
        return obj;
    }

    /**
     * json array string convert to list with javaBean
     */
    public static <T> List<T> jsonToList(String jsonArrayStr, Class<T> clazz) throws Exception {
        List<Map<String, Object>> list = mapper.readValue(jsonArrayStr, new TypeReference<List<T>>() {});
        List<T> result = new ArrayList<T>();
        for (Map<String, Object> map : list) {
            result.add(mapToJavaBean(map, clazz));
        }
        return result;
    }

    /**
     * map convert to javaBean
     */
    public static <T> T mapToJavaBean(Map map, Class<T> clazz) {
        return mapper.convertValue(map, clazz);
    }

    /**
     * json 转 Map
     * 
     * @param json
     * @return
     */
    public static Map jsonToMap(String json) {
        Map maps = null;
        try {
            maps = mapper.readValue(json, Map.class);
        }
        catch (IOException e) {
        	        	logger.error("JacksonMapper异常", e);
        }
        return maps;
    }

    /**
     * 将json数组转换为List<Map<String,Object>> json数组格式[{},{}]
     * 
     * @param jsonArray
     *            需要转换的json数组
     * @return 转换后的列表 如果转换失败返回null
     */
    @SuppressWarnings("unchecked")
    public static List<Map<String, Object>> jsonArray2List(String jsonArray) {
        try {
            return mapper.readValue(jsonArray, List.class);
        }
        catch (JsonParseException e) {
            logger.error("|JsonParseException|异常字符串|" + jsonArray, e);
        }
        catch (JsonMappingException e) {
            logger.error("|JsonMappingException|异常字符串|" + jsonArray, e);
        }
        catch (IOException e) {
            logger.error("|IOException|异常字符串|" + jsonArray, e);
        }
        return new ArrayList<Map<String, Object>>();
    }

    /**
     * 将json数组转换为List<T> json数组格式[,]
     * 
     * @param jsonArray
     *            需要转换的json数组
     * @return 转换后的列表 如果转换失败返回null
     */
    @SuppressWarnings("unchecked")
    public static List jsonArrayList(String jsonArray) {
        try {
            return mapper.readValue(jsonArray, List.class);
        }
        catch (JsonParseException e) {
            logger.error("|JsonParseException|异常字符串|" + jsonArray, e);
        }
        catch (JsonMappingException e) {
            logger.error("|JsonMappingException|异常字符串|" + jsonArray, e);
        }
        catch (IOException e) {
            logger.error("|IOException|异常字符串|" + jsonArray, e);
        }
        return new ArrayList();
    }

    /**
     * beanToMap(将javabean实体类转为map类型)
     * @param obj
     * @return
     * @return Map<String,Object>
     * @exception
     */
    public static Map<String, Object> beanToMap(Object obj) {
        Map<String, Object> params = new HashMap<String, Object>(0);
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if (!"class".equals(name)) {
                    params.put(name, propertyUtilsBean.getNestedProperty(obj, name));
                }
            }
        }
        catch (Exception e) {
        	logger.error("JacksonMapper异常", e);
        }
        return params;
    }
}
